use "scanner.sml" ;

datatype Sexpr	= Void
				| Nil
				| Pair of Sexpr * Sexpr
				| Vector of Sexpr list
				| Symbol of string
				| String of string
				| Number of int
				| Bool of bool
				| Char of char;

exception ErrorNoSexprAfterQuote;
exception ErrorNoClosingRparen;
exception ErrorMissingSexprAfterDot;
exception ErrorInvalidPairSyntax;
exception ErrorCannotReadAllSexprs of (Sexpr list) * (SchemeToken list);
exception ErrorOnlyCombinesPairs of Sexpr;
exception ErrorMoreThanOneSexpr;

signature READER =
sig
    val stringToSexpr : string -> Sexpr;
    val stringToSexprs : string -> Sexpr list;
end;

fun	makeListSexpr([], last, ret) = ret(last)
|	makeListSexpr(car :: cdr, last, ret) = makeListSexpr(cdr, last, fn (sexpr) => ret(Pair(car, sexpr)))

(***************************************************************************************
  												 						READER
***************************************************************************************)

structure Reader : READER =
struct

	(*
tokens to sexprs:		scheme token list -> sexpr list
ret sexprs and tokens:	sexpr list, scheme token list -> sexpr list
get sexprs:				scheme token list, (sexpr list, scheme token list -> sexpr list) -> sexpr list
ret sexpr and tokens:	sexpr, scheme token list -> sexpr list
ret none:				unit -> sexpr list
get sexpr:				scheme token list, (sexpr, scheme token list -> sexpr list), (unit -> sexpr list) -> sexpr list
	*)

	fun	getSexpr([], retSexprAndTokens, retNone) = retNone()
	|	getSexpr(IntToken(value) :: tokens, retSexprAndTokens, retNone) = retSexprAndTokens(Number(value), tokens)
	|	getSexpr(BoolToken(value) :: tokens, retSexprAndTokens, retNone) = retSexprAndTokens(Bool(value), tokens)
	|	getSexpr(CharToken(value) :: tokens, retSexprAndTokens, retNone) = retSexprAndTokens(Char(value), tokens)
	|	getSexpr(StringToken(value) :: tokens, retSexprAndTokens, retNone) = retSexprAndTokens(String(value), tokens)
	|	getSexpr(SymbolToken(value) :: tokens, retSexprAndTokens, retNone) = retSexprAndTokens(Symbol(value), tokens)
	|	getSexpr(QuoteToken :: tokens, retSexprAndTokens, retNone) =
			getSexpr(
				tokens,
				(fn (sexpr, toks) => retSexprAndTokens(Pair(Symbol "quote", Pair(sexpr, Nil)), toks)),
				(fn () => raise ErrorNoSexprAfterQuote)
			)
	|	getSexpr(VectorToken :: tokens, retSexprAndTokens, retNone) =
			getSexprs(
				tokens,
				(fn	(sexprs, RparenToken :: toks) => retSexprAndTokens(Vector sexprs, toks)
				|	_ => raise ErrorNoClosingRparen)
			)
	|	getSexpr(LparenToken :: tokens, retSexprAndTokens, retNone) =
			getSexprs(
				tokens,
				(fn	(sexprs, RparenToken :: toks) => makeListSexpr(sexprs, Nil, fn (sexpr) => retSexprAndTokens(sexpr, toks))
				|	([], DotToken :: toks) => raise ErrorInvalidPairSyntax
				|	(sexprs, DotToken :: toks) =>
						getSexpr(
							toks,
							(fn (last, RparenToken :: remaining) => makeListSexpr(sexprs, last, fn (lsexpr) => retSexprAndTokens(lsexpr, remaining))
							|	(_, multipleSexprsAfterDot) => raise ErrorInvalidPairSyntax),
							(fn () => raise ErrorMissingSexprAfterDot)
						)
				|	(sexprs, _) => raise ErrorNoClosingRparen)
			)
	|	getSexpr(RparenToken :: tokens, retSexprAndTokens, retNone) = retNone()
	|	getSexpr(DotToken :: tokens, retSexprAndTokens, retNone) = retNone()

	and	getSexprs(tokens, retSexprsAndTokens) =
		getSexpr(
			tokens,
			(fn (sexpr, toks) => getSexprs(toks, (fn (sexprs, remaining) => retSexprsAndTokens(sexpr :: sexprs, remaining)))),
			(fn () => retSexprsAndTokens([], tokens))
		)

	and	tokensToSexprs(tokens) =
		getSexprs(
			tokens,
			(fn	(es, []) => es
			|	(es, tokens) => raise ErrorCannotReadAllSexprs(es, tokens))
		)

	and stringToSexprs(string) = tokensToSexprs(Scanner.stringToTokens string)

	and stringToSexpr(string) =
		case (stringToSexprs string) of
			[sexpr] => sexpr
		|	_ => raise ErrorMoreThanOneSexpr;
end; (* of structure Reader *)

